/**
 * 
 */
package ro.dta.idbi.patterns;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import ro.dta.idbi.interfaces.IntegrationOperation;
import ro.dta.idbi.model.AbstractPattern;
import ro.dta.idbi.model.AutoMedUtils;
import ro.dta.idbi.model.Utils;
import uk.ac.ic.doc.automed.IntegrityException;
import uk.ac.ic.doc.automed.NotFoundException;
import uk.ac.ic.doc.automed.reps.Schema;
import uk.ac.ic.doc.automed.reps.SchemaObject;

/**
 * <b>is-a introduction transformation pattern</b><br />
 * 
 * Example of use:<br />
 * <code>add_subset (&lt;&lt;parentTable&gt;&gt;, &lt;&lt;childTable&gt;&gt;)</code>
 * <br />
 * 
 * <i>childTable</i> is made a child table of <i>parentTable</i>
 * 
 * @author Tudor Dobrila
 * 
 */
public class AddSubset extends AbstractPattern {

	/**
	 * Name of the pattern
	 */
	public static final String NAME = "Introduction of Subset";

	/**
	 * Description of the pattern
	 */
	public static final String DESCRIPTION = "Introduce a subset constraint";

	/**
	 * Name of the command associated with the pattern
	 */
	public static final String COMMAND = "add_subset";

	/**
	 * Integration phase during which the command is applied
	 */
	public static final EnumSet<IntegrationOperation> OPERATION = EnumSet
			.of(IntegrationOperation.MERGING);

	/**
	 * Parent table
	 */
	private String parentTbl;

	/**
	 * Child table
	 */
	private String childTbl;

	/**
	 * is-a introduction pattern class constructor
	 * 
	 * @param sourceSchema
	 *            Source schema over which the transformation is applied
	 */
	public AddSubset(final Schema sourceSchema) throws NotFoundException, IntegrityException {
		super(sourceSchema);

		pattern = Pattern.compile("^" + COMMAND + "[ ]*\\((" + TABLE_REGEX + ")" + COMMA_REGEX
				+ "(" + TABLE_REGEX + ")\\)$");
	}

	/**
	 * is-a introduction pattern class constructor
	 * 
	 * @param sourceSchema
	 *            Name of source schema over which the transformation is applied
	 */
	public AddSubset(final String sourceSchema) throws NotFoundException, IntegrityException {
		this(Schema.getSchema(sourceSchema));
	}

	@Override
	protected List<String> getPrimitiveCommands() throws NotFoundException, IntegrityException {
		List<String> result = new ArrayList<String>();
		final SchemaObject parentObj = sourceSchema.getSchemaObject("<<" + parentTbl + ">>");
		final SchemaObject childObj = sourceSchema.getSchemaObject("<<" + childTbl + ">>");

		if (AutoMedUtils.getSupertypeFK(sourceSchema, parentObj, childObj) != null) {
			throw new IllegalArgumentException(childTbl + " is already a child of " + parentTbl);
		}

		// Construct the FK
		StringBuilder cmd = new StringBuilder();
		final List<String> parentPK = AutoMedUtils.getPK(sourceSchema, parentObj);
		cmd.append("add (").append(Utils.genFKRepresentation(childTbl, parentTbl, parentPK))
				.append(")");
		result.add(cmd.toString());
		
		return result;
	}

	@Override
	protected boolean verify() {
		// TODO Auto-generated method stub
		return true;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ro.dta.idbi.model.AbstractPattern#parse(java.lang.String)
	 */
	@Override
	protected void parse(final String trans) {
		final Matcher matcher = pattern.matcher(trans);
		matcher.find();

		parentTbl = parseTableName(matcher.group(1));
		childTbl = parseTableName(matcher.group(2));
	}

	/**
	 * Set the parent table
	 * 
	 * @param parentTbl
	 *            The new parent table
	 */
	public void setParentTbl(final String parentTbl) {
		this.parentTbl = parentTbl;
	}

	/**
	 * @return The parent table
	 */
	public String getParentTbl() {
		return parentTbl;
	}

	/**
	 * Set the child table
	 * 
	 * @param childTbl
	 *            The new child table
	 */
	public void setChildTbl(final String childTbl) {
		this.childTbl = childTbl;
	}

	/**
	 * @return The child table
	 */
	public String getChildTbl() {
		return childTbl;
	}

}
